Gopher Proxy
gopher.conman.org:70 gopher.conman.org:70/0Boston:Src:Lua/put.lua
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#!/usr/bin/env Lua
-- GPL2+ Copyright 2026 by Sean Conner
-- luacheck: ignore 611
-- ************************************************************************
-- for PUT:
-- 201 Created
-- 202 Accepted entry-post-hook failed
-- 400 Bad Request
-- 401 Unauthorized
-- 408 Timed out
-- 422 Unprocess Entiry entry-pre-hook failed
-- 500 Internal Server Error
-- ************************************************************************
local tls = require "org.conman.net.tls"
local tcp = require "org.conman.net.tcp"
local url = require "org.conman.parsers.url"
local magic = require "org.conman.fsys.magic"
local fsys = require "org.conman.fsys"
local http = require "org.conman.parsers.http-client"
local getopt = require "org.conman.getopt".getopt
local ih = require "org.conman.parsers.ih"
local base64 = require "org.conman.base64"()
local uurl = require "url-util"
local http_status = require "org.conman.const.http-response"
local zlib = require "zlib"
local headers = ih.headers(ih.generic)
magic:flags('mime')
-- ************************************************************************
local function errmsg(...)
io.stderr:write(string.format(...),'\n')
return 1
end
-- ************************************************************************
local function msg(...)
io.stdout:write(string.format(...),'\n')
end
-- ************************************************************************
local function request(conn,method,location,closef,user,mimetype,body)
local path do
if location.query then
path = string.format("%s?%s",location.path,location.query)
else
path = location.path
end
end
conn:write(
string.format("%s %s HTTP/1.1\r\n",method,path),
string.format("Host: %s:%d\r\n",location.host,location.port),
"User-Agent: mod-blog-updater/1.2\r\n",
"Accept: */*\r\n"
)
if mimetype then
conn:write(
string.format("Content-Type: %s\r\n",mimetype),
string.format("Content-Length: %d\r\n",#body)
)
end
if closef then
conn:write("Connection: close\r\n")
end
if user then
conn:write(string.format("Authorization: %s\r\n",user))
end
conn:write("\r\n")
conn:flush()
if body then
while #body > 0 do
local data = body:sub(1,1024)
conn:write(data)
conn:flush()
body = body:sub(1025,-1)
end
end
local r = conn:read("l")
local h = conn:read("h")
local res = http.response:match(r)
local hdr = http.headers:match(h)
if hdr['Content-Length'] then
body = conn:read(hdr['Content-Length'])
elseif hdr['Transfer-Encoding'] == 'chunked' then
body = ""
repeat
local line = conn:read("l")
if not line then break end
local len = tonumber(line,16)
if not len then break end
body = body .. (conn:read(len) or "")
conn:read("l")
until len == 0
else
body = ""
end
if hdr['Content-Encoding'] == 'gzip' then
local s = zlib.inflate(body)
body = s:read("*a")
end
return res.status,body
end
-- ************************************************************************
local function loadentry(filename)
local f,err = io.open(filename,"r")
if not f then
errmsg("%s: %s",filename,err)
return
end
local body = f:read("*a")
f:close()
if #body == 0 then
errmsg("%s: empty",filename);
return
end
local hdrs = headers:match(body)
if not hdrs then
errmsg("%s: not a proper entry",filename)
return
end
if not hdrs['Date'] then
hdrs['Date'] = os.date("%Y/%m/%d")
end
return body,hdrs['Date']
end
-- ************************************************************************
local function usage()
io.stderr:write(string.format([[
usage: %s [options] entryfile [files...]
-b | --blog blogref
-h | --help
]],arg[0]))
os.exit(1,true)
end
-- ************************************************************************
local CONF = "/home/spc/.config/mod-blog-put.config"
local BLOG = 'default'
local BASEURL
local USER
local opts =
{
{ "b" , "blog" , true , function(b) BLOG = b end },
{ "h" , "help" , false , function() usage() end },
}
local fi = getopt(arg,opts)
if not arg[fi] then
os.exit(errmsg("missing entry file"),true)
end
do
local confenv = {}
local conf,err = loadfile(CONF,"t",confenv)
if not conf then
os.exit(errmsg("%s: %s",CONF,err),true)
end
conf()
if not confenv[BLOG] then
os.exit(errmsg("%s: missing %q config block",CONF,BLOG),true)
end
BASEURL = confenv[BLOG].url
if not BASEURL then
os.exit(errmsg("%s: missing %s.url directive",CONF,BLOG),true)
end
USER = confenv[BLOG].user
if USER then
USER = "Basic " .. base64:encode(USER)
end
end
-- ************************************************************************
local body,date = loadentry(arg[fi])
if not body then
os.exit(1,true)
end
local base = url:match(BASEURL)
local path = url:match(date .. '/' .. fsys.basename(arg[fi]))
local location = uurl.merge(base,path)
local conn,err do
if location.scheme == 'https' then
conn,err = tls.connect(location.host,location.port)
else
conn,err = tcp.connect(location.host,location.port)
end
end
if not conn then
os.exit(errmsg("%s: %s",location.host,err),true)
end
-- --------------------------------
-- Get next entry URL
-- --------------------------------
local newurl do
local status,bodyg
local basen = url:match(BASEURL)
local pathn = url:match("/boston.cgi?cmd=last&date="..date)
location = uurl.merge(basen,pathn)
msg("GET '%s'",uurl.toa(location))
status,bodyg = request(conn,"GET",location)
if status ~= http_status.SUCCESS.OKAY then
os.exit(errmsg("%d '%s'",status,uurl.toa(location)),true)
end
local front,part = bodyg:match("^(.*)(%d+)$")
part = tonumber(part) + 1
newurl = front .. part
end
location = url:match(newurl)
-- ------------------------------------------
-- PUT the new entry
-- ------------------------------------------
msg("PUT '%s' (%d)",uurl.toa(location),#body)
local status = request(conn,"PUT",location,fi == #arg,USER,"application/mod_blog",body)
if status ~= http_status.SUCCESS.CREATED then
os.exit(errmsg("PUT: %d '%s'",status,uurl.toa(location)),true)
end
-- -----------------------------------
-- PUT any other files specified
-- -----------------------------------
local excode = 0
for i = fi + 1 , #arg do
local f,err2 = io.open(arg[i],"rb")
if f then
body = f:read("*a")
f:close()
local pathf = url:match(date .. '/' .. fsys.basename(arg[i]))
local locationf = uurl.merge(base,pathf)
msg("PUT '%s' (%d)",uurl.toa(locationf),#body)
status = request(conn,"PUT",locationf,i==#arg,USER,magic(body,true),body)
if status ~= http_status.SUCCESS.CREATED then
excode = errmsg("PUT: %d '%s'",status,uurl.toa(locationf))
end
else
excode = errmsg("%s: %s",arg[i],err2)
end
end
os.exit(excode,true)
.
you're on gopher.conman.org^70/0Boston:Src:Lua/put.lua
back link is gopher.conman.org:70/1Boston:Src:Lua/